//
// Created by Administrator on 2018/5/29.
//
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include "com_lututong_uarttools_UartJniTool.h"
#include <android/log.h>
#include <linux/ioctl.h>
#include <jni.h>
#include <malloc.h>
#include <memory.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>

#define UART_DEVICE         "/dev/ttyS5"

#define LOG_TAG   "UART_JNI_TOOL"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

#define JAVA_BUFFER_SIZE    200

static int serial_fd = -1;
static pthread_t rxThread; // read moniter thread
static JavaVM *gs_jvm = NULL;
static jobject gs_object = NULL;
static char pJavaBuffer[JAVA_BUFFER_SIZE];
static int recvDataLen = 0;

int uart_speed(int speed) {
    switch (speed) {
        case 9600:
            return B9600;
        case 19200:
            return B19200;
        case 38400:
            return B38400;
        case 57600:
            return B57600;
        case 115200:
            return B115200;
        case 230400:
            return B230400;
        case 460800:
            return B460800;
        case 500000:
            return B500000;
        case 576000:
            return B576000;
        case 921600:
            return B921600;
        default:
            return B57600;
    }
}

int init_serial(int speed) {
    struct termios ti;
    int baudenum;
    int fd_bt;

   fd_bt = open(UART_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
   //fd_bt = open(UART_DEVICE, O_RDWR | O_NOCTTY );
    if (fd_bt < 0) {
        LOGE("Can't open serial port %s\n", UART_DEVICE);
        return -1;
    }
    else
        LOGI("open %s successfully!!! fd_bt=%d", UART_DEVICE, fd_bt);

    tcflush(fd_bt, TCIOFLUSH);

    if (tcgetattr(fd_bt, &ti) < 0) {
        LOGE("Can't get serial port setting\n");
        close(fd_bt);
        fd_bt=-1;
        return -1;
    }

    cfmakeraw(&ti);

    ti.c_cflag |= CLOCAL;
    ti.c_lflag = 0;

    ti.c_cflag &= ~CRTSCTS;
    ti.c_iflag &= ~(IXON | IXOFF | IXANY);

    /* Set baudrate */
    baudenum = uart_speed(speed);
    if ((baudenum == B115200) && (speed != 115200)) {
  //  if ((baudenum == B9600) && (speed != 9600)) {
        LOGE("Serial port baudrate not supported!\n");
        close(fd_bt);
        fd_bt=-1;
        return -1;
    }

    cfsetospeed(&ti, baudenum);
    cfsetispeed(&ti, baudenum);

    if (tcsetattr(fd_bt, TCSANOW, &ti) < 0) {
        LOGE("Can't set serial port setting\n");
        close(fd_bt);
        fd_bt=-1;
        return -1;
    }

    tcflush(fd_bt, TCIOFLUSH);

    return fd_bt;
}

static void thread_exit(int signo)
{
    pthread_t tid = pthread_self();
    LOGI("Thread %lu exits\n", tid);
    pthread_exit(0);
}

void *bt_rx_monitor(void *ptr)
{
    char ucRxBuf;
    int ret;
    JNIEnv *env;
    jclass ClassCJM;
    struct timeval timeout;
    fd_set read_fds;
    jmethodID MethodGetUartDataHandler;
    jobject getUartDataHandlerDescriptor;

    recvDataLen = 0;

    LOGI("Thread %lu starts\n", rxThread);

//    while(1)
//    {
//        sleep(100);
//    }

#if 1
    if (gs_jvm != NULL) {
        gs_jvm->AttachCurrentThread((JNIEnv **)&env, NULL);
        ClassCJM = env->GetObjectClass(gs_object);

        MethodGetUartDataHandler = env->GetMethodID(ClassCJM, "getUartDataHandler", "([BI)V");
        //etUartDataHandlerDescriptor = env->NewObject(ClassCJM, MethodGetUartDataHandler);
    }
#endif
    while (1) {
          if(serial_fd >0)
          {
              timeout.tv_sec=1;
              timeout.tv_usec=0;
              FD_ZERO(&read_fds);
              FD_SET(serial_fd,&read_fds);
              ret=select(serial_fd+1,&read_fds,NULL,NULL,&timeout);
              if(ret < 0){
                  LOGE("Select Error ret = %d\n",ret);
                  return 0;
              }else if(ret == 0){ // Select Timeout
                    if(recvDataLen > 0 && gs_object){
                        //接收数据超时，将已经接收到的数据传递给Java层。
                        jbyteArray dataBytes = env->NewByteArray(recvDataLen);
                        env->SetByteArrayRegion(dataBytes, 0, recvDataLen, (const jbyte *)pJavaBuffer);
                        env->CallVoidMethod(gs_object, MethodGetUartDataHandler, dataBytes, recvDataLen);
                        env->DeleteLocalRef(dataBytes);
                        recvDataLen = 0;
                    }
              }else{
                  if (FD_ISSET(serial_fd, &read_fds)){
                      if((recvDataLen < JAVA_BUFFER_SIZE) && (pJavaBuffer != NULL)){
                          read(serial_fd, &pJavaBuffer[recvDataLen++], 1);
                          //LOGI("Recv0 data = %02X\n",pJavaBuffer[recvDataLen-1]);
                      }else{
                          //buffer已经填满，先将数据传递给Java层，后接收新数据。
                          jbyteArray dataBytes = env->NewByteArray(recvDataLen);
                          env->SetByteArrayRegion(dataBytes, 0, recvDataLen, (const jbyte *)pJavaBuffer);
                          env->CallVoidMethod(gs_object, MethodGetUartDataHandler, dataBytes, recvDataLen);
                          env->DeleteLocalRef(dataBytes);
                          recvDataLen = 0;

                          read(serial_fd, &pJavaBuffer[recvDataLen++], 1);
                          //LOGI("Recv1 data = %02X\n",pJavaBuffer[recvDataLen-1]);

                      }
                  }
              }
          }
    }
//#endif
    return 0;
}

int uart_tool_start(void)
{
    serial_fd = init_serial(115200);//115200
    if (serial_fd < 0) {
        LOGE("Initialize serial port to Device fails\n");
        return -1;
    }

    //signal(SIGRTMIN, thread_exit);
    /* Create RX monitor thread */
    pthread_create(&rxThread, NULL, bt_rx_monitor, NULL);

    LOGI("UART TOOL mode start\n");

    return 0;
}

void uart_tool_stop(void)
{
    /* Wait until thread exit */
    pthread_kill(rxThread, 0);
    //pthread_join(rxThread, NULL);
    //signal(SIGRTMIN, SIG_DFL);

    close(serial_fd);
    serial_fd = -1;
}

/*
 * Class:     com_lututong_uarttools_UartJniTool
 * Method:    uartToolStart
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_lututong_uarttools_UartJniTool_uartToolStart(JNIEnv *env, jobject obj)
{
    int ret = -1;

    //get java VM and object
    env->GetJavaVM(&gs_jvm);
    gs_object = env->NewGlobalRef(obj);

    // open and init uart
    ret = uart_tool_start();

    return ret;
}

/*
 * Class:     com_lututong_uarttools_UartJniTool
 * Method:    uartToolStop
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_lututong_uarttools_UartJniTool_uartToolStop(JNIEnv *env, jobject obj)
{
    uart_tool_stop();

    return 0;
}

/*
 * Class:     com_lututong_uarttools_UartJniTool
 * Method:    StartTofHandler
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_lututong_uarttools_UartJniTool_StartTofHandler(JNIEnv *env, jobject obj)
{
    unsigned char startCmd[16] = {0x55, 0xAA, 0x0C, 0x01, 0x00, 0xB2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x00, 0xFA};
    int ret = -1;
    if(serial_fd >0){
        ret = write(serial_fd, startCmd, 16);
        //for (int i = 0; i < 7; i++)
           //ret =  write(serial_fd, &buffer[0], 1);
    }

    if(ret > 0)
        LOGI("[cai.zhong]Send Start Cmd is successfully!\n");
    return 0;
}

/*
 * Class:     com_lututong_uarttools_UartJniTool
 * Method:    CloseTofHandler
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_lututong_uarttools_UartJniTool_CloseTofHandler(JNIEnv *env, jobject obj)
{
    unsigned char stopCmd[16] = {0x55, 0xAA, 0x0C, 0x03, 0x00, 0xB2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xFA};
    int ret = -1;
    if(serial_fd >0){
        ret = write(serial_fd, stopCmd, 16);
        //for (int i = 0; i < 7; i++)
        //ret =  write(serial_fd, &buffer[0], 1);
    }

    if(ret > 0)
        LOGI("[cai.zhong]Send Stop Cmd is successfully!\n");
    return 0;
}
